<?php

namespace gateim\library\tool;

/**
 * 验证数据是否合格
 */
class Validator
{
    // 规则
    protected $rule =   [
        'type' => 'require|string',
        'action' => 'require|string',
        'data' => 'require|json',
        'fd' => 'require|number',
        'uid' => 'require|number',
        'group_id' => 'require|number',
        'msg' => 'require|string',
    ];

    // 提示语
    protected $message  =   [
        'type'  => 'type 必须为字符串',
        'action'  => 'action 必须为字符串',
        'data'  => 'data 必须为json字符串',
        'fd'  => 'fd 必须为数字',
        'uid'  => 'uid 必须为数字',
        'group_id'  => 'group_id 必须为数字',
        'msg'  => 'group_id 必须为字符串',
    ];

    // 场景
    public $scene = [
        'valid' => ['type','action','data'], // 验证客户端的数据
        'bind_fd_uid' => ['fd','uid'], // 将fd与uid绑定
        'getFdAll' => [], // 获取所有fd
        'getUserSonFd' => ['uid'], // 获取uid所有的fd
        'getFdOnUid' => ['fd'], // 获取某个fd所属的uid
        'delUidAndFd' => ['uid'], // 移除uid以及它的所有fd
        'delFd' => ['fd'], // 移除某个fd
        'uidToGroupID' => ['uid','group_id'], // 将 uid 加入一个 group_id 中
        'uidRemoveGroupId' => ['uid','group_id'], // 将 uid 移出 group_id
        'getUidToGroupId' => ['uid'], // 获取 uid 加入的所有 group_id
        'getGroupIdInUid' => ['group_id'], // 获取 group_id 中的所有 uid
        'uidRemoveAllGroupId' => ['uid'], // 将 uid 移除所有 group_id
        'removeGroupId' => ['group_id'], // 解散 group_id
        'sendFds' => ['msg'], // 给所有 fd 发送消息
        'sendFd' => ['fd','msg'], // 给指定 fd 发送消息
        'sendUid' => ['uid','msg'], // 给指定 uid 发送消息
        'sendGroupId' => ['group_id','msg'], // 给指定 group_id 发送消息
        'getFdsNum' => [], // 获取在线的 fd 数量
        'getUidsNum' => [], // 获取在线的 uid 数量
        'getGroupIdInUidNum' => ['group_id'], // 获取 group_id 中 uid 的数量
        'getUidToGroupIDNum' => ['uid'], // 获取 uid 加入 group_id 的数量
        'getUidBindFdNum' => ['uid'], // 获取 uid 中 fd 的数量
        'isUidOnline' => ['uid'], // 判断 uid 是否在线
        'isGroupIdOnline' => ['group_id'], // 判断 group_id 是否存在
    ];

    // 验证方法，并返回新数组
    public function valid($type,$action,$data){
        $valid = $this -> sceneRule('valid',['type'=>$type,'action'=>$action,'data'=>$data]);
        if($valid['code'] == 0){
            return [$valid];
        }

        // im类型的，需要验证场景
        if($type == 'im'){
            $data = json_decode($data,true); // 多个参数

            $res = $this -> sceneRule($action,$data); // 验证场景
            if($res['code'] == 0){
                return [$res];
            }
        }

        return [
            $type,$action,$data
        ];
    }

    // 验证场景
    private function sceneRule($scene,$data){
        if(!isset($this -> scene[$scene])){
            return [
                'code' => 0,
                'msg' => '场景不存在'
            ];
        }
        foreach ($this -> scene[$scene] as $val){
            if(!isset($data[$val])){
                return [
                    'code' => 0,
                    'msg' => '缺少'.$val.'字段'
                ];
            }
            $res = $this -> fieldRule($val,$data[$val]);
            if($res['code'] == 0){
                return $res;
            }
        }
        return [
            'code' => 1,
            'msg' => '验证通过'
        ];
    }

    // 验证字段格式是否正确
    private function fieldRule($key='',$value=''){
        if(!isset($this -> rule[$key]) || !isset($this -> message[$key])){
            return [
                'code' => 0,
                'msg' => $key.'字段在rule或message中无配置'
            ];
        }

        $rule = explode('|',$this -> rule[$key]);
        foreach ($rule as $item){
            switch ($item){
                case 'require':
                    if(empty($value)){
                        return [
                            'code' => 0,
                            'msg' => $this -> message[$key]
                        ];
                    }
                    break;
                case 'string':
                    if(!is_string($value)){
                        return [
                            'code' => 0,
                            'msg' => $this -> message[$key]
                        ];
                    }
                    break;
                case 'json':
                    if(!$this -> is_json($value)){
                        return [
                            'code' => 0,
                            'msg' => $this -> message[$key]
                        ];
                    }
                    break;
                case 'number':
                     if(!is_numeric($value)){
                         return [
                             'code' => 0,
                             'msg' => $this -> message[$key]
                         ];
                     }
                    break;
            }
        }

        return [
            'code' => 1,
            'msg' => '验证通过'
        ];
    }

    // 判断字符串是否json
    function is_json($string) {
        if(!is_string($string)){
            return false;
        }
        json_decode($string);
        return (json_last_error() == JSON_ERROR_NONE);
    }

}
